package com.gufe.controller.webSocket.Handler;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gufe.constant.JwtClaimsConstant;
import com.gufe.properties.JwtProperties;
import com.gufe.result.WxMessageResult;
import com.gufe.service.user.message.MessageService;
import com.gufe.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import static com.gufe.controller.webSocket.WebSocketStarter.USER_ID_KEY;
import static com.gufe.controller.webSocket.WebSocketStarter.userChannels;


//自定义websocket服务器处理逻辑
@Slf4j
@Component
@ChannelHandler.Sharable // 标记为可共享
public class HandlerWebSocket extends SimpleChannelInboundHandler<Object> {

    @Autowired
    MessageService messageService;

    @Autowired
    JwtProperties jwtProperties;

    //有客户端连接时触发
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端:{}尝试连接中", ctx.channel().remoteAddress().toString());
    }

    //有客户端断开时触发
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 移除用户Channel映射
        String userId = ctx.channel().attr(USER_ID_KEY).getAndSet(null);
        if (userId != null) {
            userChannels.remove(userId);
            //更新住状态为离线
            messageService.setOnlieStatus(Long.valueOf(userId),0);
            log.info("用户 {} 已下线，当前在线用户数：{}", userId, userChannels.size());
        }

        log.info("客户端 {} 断开连接", ctx.channel().remoteAddress());
        super.channelInactive(ctx);
    }

    //消息中转
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (!(msg instanceof TextWebSocketFrame)) return;
        String msgId = null;
        try {
            String json = ((TextWebSocketFrame) msg).text();
            JsonNode node = new ObjectMapper().readTree(json);
            if (node == null) {
                //json校验失败
                ctx.writeAndFlush(WxMessageResult.responseErro());
                return;
            }
            msgId = node.get("msgId").asText();
            String toUserId = node.get("toUserId").asText();
            String msgContent = node.get("content").asText();

            // 获取发送方自己的ID
            String fromUserId = ctx.channel().attr(USER_ID_KEY).get();
            if (fromUserId == null) {
                ctx.writeAndFlush(WxMessageResult.responseErro(msgId));
                return;
            }

            //无论是否在线都要通过数据库持久化消息
            //将消息刷向数据库逻辑
            boolean insertMsg = messageService.insertMsg(Long.valueOf(fromUserId), Long.valueOf(toUserId), msgContent);
            //同步数据库失败
            if (!insertMsg) {
                ctx.writeAndFlush(WxMessageResult.responseErro(msgId));
                return;
            }

            // 构建发送消息
            TextWebSocketFrame textWebSocketFrame = WxMessageResult.delieveMessage(fromUserId, msgContent);

            // 查找目标Channel并发送
            Channel targetChannel = userChannels.get(toUserId);

            //确保用户在线直接通过socket发送
            if (targetChannel != null && targetChannel.isActive()) {
                targetChannel.writeAndFlush(textWebSocketFrame);
            }

            //构建成功的消息回调
            ctx.writeAndFlush(WxMessageResult.responseSuccess(msgId));
            return;
        } catch (Exception e) {
            log.error("消息处理失败", e);
            //json校验失败
            ctx.writeAndFlush(WxMessageResult.responseErro());
        }
        //构建失败的回调
        if (msgId != null) {
            ctx.writeAndFlush(WxMessageResult.responseErro(msgId));
        }
    }


    @Override
    //拦截器握手检验
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        //加入段断点校验
        // 判断事件类型是否是 WebSocket 握手状态事件
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            // 握手成功，获取 HandshakeComplete 对象
            WebSocketServerProtocolHandler.HandshakeComplete handshakeComplete =
                    (WebSocketServerProtocolHandler.HandshakeComplete) evt;
            // 提取请求 URI 和 Token
            String requestUri = handshakeComplete.requestUri();
            if (!checkToken(ctx, requestUri)) {
                ctx.close();//断开连接
                log.info("链接{}的token校验失败，断开链接", ctx.channel().remoteAddress());
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    //token校验拦截器
    private boolean checkToken(ChannelHandlerContext ctx, String url) {
        if (url == null) {
            return false;
        }
        if (!url.contains("?token=")) {
            return false;
        }
        String[] split = url.split("\\?token=");
        if (split.length != 2) {
            return false;
        }
        String tokenAndType = split[1];
        if (tokenAndType == null || tokenAndType.isEmpty()) {
            return false;
        }

        String token = tokenAndType.split("&type=")[0];
        String userType = tokenAndType.split("&type=")[1];

        String userId = null;
        try {
            if ("User".equals(userType)) {
                Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
                userId = claims.get(JwtClaimsConstant.USER_ID).toString();
            } else {
                Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
                userId = claims.get("userId").toString();
            }
        } catch (Exception e) {
            log.info("jwt解析失败{}", e.getMessage());
        }

        if (userId == null) {
            ctx.close();
            return false;
        }
        //存储当前发送请求的用户id
        ctx.channel().attr(USER_ID_KEY).set(userId);
        // 绑定用户ID到Channel
        userChannels.put(userId, ctx.channel());
        log.info("连接成功，用户id：{}，通道：{}", userId, ctx.channel().remoteAddress().toString());
        //更新用户在线状态
        messageService.setOnlieStatus(Long.valueOf(userId),1);
        return true;
    }
}
